`include "PRV564Config.v"
`include "PRV564Define.v"

module BTB(
//-------------------Global SIgnal----------------
    input                   clk, rst,
//------------------read port1---------------------
    input [`XLEN-1:0]       rd_PC,					//输入PC
    output reg [1:0]        rd_predicted,			//对外输出的信号, 表示rd_PC是跳转指令，此时rd_predicted_PC是有效数据
    output reg [`XLEN-1:0]  rd_predicted_PC,	    //从buffer中得到的预测PC
//----------------IDU write and check port--------
    input                   wr_req,				    //写请求信号
    input [`XLEN-1:0]       wr_PC,					//要写入的分支PC
    input [`XLEN-1:0]       wr_predicted_PC,		//要写入的预测PC
    input                   wr_predicted_state_bit	//要写入的预测状态位
);
parameter BUFFER_ADDR_LEN=4;
parameter BUFFER_SIZE   = 1<<BUFFER_ADDR_LEN;
parameter TAG_LEN       = 64-BUFFER_ADDR_LEN-2;

    reg [TAG_LEN-1:0]   tag_pc          [0:BUFFER_SIZE-1]; 
    reg [`XLEN-1:0]     predicted_pc    [0:BUFFER_SIZE-1];
    reg [1:0]           predicted_state [0:BUFFER_SIZE-1];  //2bit 饱和计数器
    reg                 predicted_valid [0:BUFFER_SIZE-1];

    wire [TAG_LEN-1:0]          rd_pc_tag;
    wire [BUFFER_ADDR_LEN-1:0]  rd_pc_index;
    wire [1:0]                  rd_pc_offset;
    wire [TAG_LEN-1:0]          wr_pc_tag;
    wire [BUFFER_ADDR_LEN-1:0]  wr_pc_index;
    wire [1:0]                  wr_pc_offset;

assign {rd_pc_tag,rd_pc_index,rd_pc_offset}=rd_PC;
assign {wr_pc_tag,wr_pc_index,wr_pc_offset}=wr_PC;
//-------------------------读口------------------------------
always@(*)begin
    if((tag_pc[rd_pc_index]==rd_pc_tag) && predicted_valid[rd_pc_index])begin   //表项命中
        rd_predicted = predicted_state[rd_pc_index];
    end
    else begin
        rd_predicted = 2'b0;
    end
end
always@(*)begin
   rd_predicted_PC = predicted_pc[rd_pc_index];
end
//-------------------写表项，计数器值更新----------------------
integer i;
always@(posedge clk)begin
    if(rst)begin
        for(i=0; i<BUFFER_SIZE; i=i+1)begin
            tag_pc[i]           <=0;
            predicted_pc[i]     <=0;
            predicted_valid[i]  <=0;
        end
    end
    else if(wr_req)begin
        tag_pc[wr_pc_index]         <=wr_pc_tag;
        predicted_pc[wr_pc_index]   <=wr_predicted_PC;
        predicted_valid[wr_pc_index]<=1'b1;
    end
end
integer j;
always@(posedge clk)begin
    if(rst)begin
        for(j=0; j<BUFFER_SIZE; j=j+1)begin
            predicted_state[j]  <=0;
        end
    end
    else if(wr_req)begin
        if((wr_pc_tag==tag_pc[wr_pc_index]) & predicted_valid[wr_pc_index])begin              //当前写的表项和已有的表项重合
            case(predicted_state[wr_pc_index])
                2'b00 : predicted_state[wr_pc_index] <= wr_predicted_state_bit ? 2'b01 : 2'b00;
                2'b01 : predicted_state[wr_pc_index] <= wr_predicted_state_bit ? 2'b10 : 2'b00;
                2'b10 : predicted_state[wr_pc_index] <= wr_predicted_state_bit ? 2'b11 : 2'b01;
                2'b11 : predicted_state[wr_pc_index] <= wr_predicted_state_bit ? 2'b11 : 2'b10;
            endcase
        end
        else begin
            predicted_state[wr_pc_index] <= wr_predicted_state_bit ? 2'b11 : 2'b00;  //如果是一个新的表项，就定位强跳转或强不跳转
        end    
    end
end
endmodule
